/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package proyecto;

import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author Luis Romero
 */
public class Nucleo extends Thread {
    long tInicio, tFinal;
    IF fetch;
    ID id;
    EX ex;
    Mem m;
    WB wb;
    int PC; // El PC tiene que estar en fetch para que sepa que instrucccion traer
    int ID;
    int Quantum;
    CacheInstrucciones CI;
    CacheDatos CD;
    Registros Reg;
    MemoriaPrincipal MP;
    Nucleo alt1;
    Nucleo alt2;
    Cola hilos;
    Controlador C;
    final Object lock;
    Reloj reloj;
    //ThreadGroup conjunto;

    LectorArchivos archivito;

    Nucleo() {
        PC = 0;
        CI = new CacheInstrucciones();
        CD = new CacheDatos();
        Reg = new Registros();
        lock = new Object();
        this.setName("Nucleo"+ID);
        archivito = new LectorArchivos();
    }

    public void parar() {
        synchronized (lock) {
            try {
                //System.out.println("Parar Nucleo");
                lock.wait();
            } catch (InterruptedException e) {
                Logger.getLogger(ID.class.getName()).log(Level.SEVERE, null, e);
            }
        }
    }

    public void seguir() {
        //System.out.println("Seguir Nucleo");
        synchronized (lock) {
            lock.notify();
        }
    }

    @Override
    public void run() {
        tInicio = System.nanoTime();
        Ejecutar();
        this.C.inter.p.actualizarDatos(Reg.Registros, ID);
    }

    public void setPC(int npc) {
        fetch.PC = npc;
    }

    public void setNucleos(Nucleo n1, Nucleo n2) {
        alt1 = n1;
        alt2 = n2;
    }

    public void setID(int x) {
        ID = x;
    }

    public void setControlador(Controlador cont) {
        C = cont;
    }

    public void setMemoria(MemoriaPrincipal mp) {
        MP = mp;
        CI.setMemoria(mp);
        CD.setMemoria(mp);
    }

    public void setCola(Cola c) {
        hilos = c;
    }

    public void setQuantum(int q){
        Quantum=q;
    }

    public synchronized void iniciarHilos(){
        fetch = new IF(CI);
        id = new ID(Reg);
        ex = new EX();
        m = new Mem(CD);
        wb = new WB(Reg);
        
        reloj = new Reloj(fetch,id,ex,m,wb);
        reloj.setMaxQuantum(Quantum);
        fetch.setReloj(reloj);
        id.setReloj(reloj);
        ex.setReloj(reloj);
        m.setReloj(reloj);
        wb.setReloj(reloj);
        
        fetch.setEtapas(id);
        id.setEtapa(fetch, ex);
        ex.setEtapas(m, id);
        m.setEtapas(wb, ex);
        wb.setEtapas(m,fetch);
        wb.setNucleoP(this);
        fetch.setNucleo(this);
        id.setNucleo(this);
        ex.setNucleo(this);
        m.setNucleo(this);
        
        reloj.start();
        
        System.out.println("Inicializando hilos");
        fetch.start();
        this.parar();
        id.start();
        this.parar();
        ex.start();
        this.parar();
        m.start();
        this.parar();
        wb.start();
        this.parar();
        System.out.println("Termina Inicializando");
    }

    public void Ejecutar() {
        System.out.println("Inicio de nucleo");
       
        int[] hilo = C.PedirHilo();
        while(hilo!=null){
            iniciarHilos();
            System.out.println("Empezando el hilo");
            int npc = hilo[1];
            setPC(npc);
            if(hilo[0]!=-1){
                MP.RecuperaRegistros(Reg, hilo[0]);
            }
            System.out.println("Seguir FEN");
            fetch.seguir();
            System.out.println("Para el nucleo");
            //this.parar();
            System.out.println("Sigue el nucleo");
            System.out.println("Nucleo termino el hilo");
            tFinal = System.nanoTime();
            System.out.println("La duracion del hilo "+ID+" es de "+(tFinal-tInicio)+";");
            try {
                System.out.println("Esperando a que mueran los hilos");                
                fetch.join();
                id.join();
                ex.join();
                m.join();
                wb.join();
                System.out.println("todos muertos");
                int ticks = reloj.getTicks();
            } catch (InterruptedException ex) {
                Logger.getLogger(Nucleo.class.getName()).log(Level.SEVERE, null, ex);
            }
           
            archivito.EscribirResultados(Reg);
            hilo = C.PedirHilo();
        }        
    }
}
